#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <string.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <ldap.h>
#include "log.h"


struct sesionLDAP {
    int version;
    int ldapPort;
    int rc;
    char *ldapHost;
    char *loginDN;
    char *password;
    char *dn;
    LDAP *ld;
}sesionLDAP;

struct sesionLDAP sesion;
char grupoElegido[1024];
char ipLDAP[16];
int puertoSSL;
char pathServerKEY[300];
char LDAP_Port[6];
char LDAP_DN[128];
char LDAP_Pass[80];
int PID;

int obtenerDatosConfig(void);
int OpenListener(int port);
SSL_CTX* InitServerCTX(void);
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile);
void ShowCerts(SSL* ssl);
void Servlet(SSL* ssl);
int funcionHelp(SSL *ssl);
void eliminarDuplicados(char *listaOriginal, char *listaLimpia);
char* procesoComandos (char* comando, char* parametro,SSL* ssl);
int listarNewsgroups(SSL* socket);
int listarArticles(SSL* ssl, char *groupName);
int mostrarArticle(SSL* ssl, char *mensajeID);
int mostrarBody(SSL * ssl, char *mensajeID);
int mostrarHead(SSL * ssl, char *mensajeID);
int mostrarStat(SSL * ssl, char *mensajeID);
void cadenaID (char *mensajeID);
int entroif;
char grupo [1024];
char articleID [1024];
                                                                    
int main(int count, char *strings[]){

	SSL_CTX *ctx;
	int server;
	char *portnum;

	PID=getpid(); /* Obtiene el ID del Proceso*/

	if (obtenerDatosConfig() == 1) {
        printf("ERROR: No se ha podido leer correctamente el archivo de configuracion");                     
		escribirLog("NNTPServerBAM",PID,"ERROR: No se ha podido leer correctamente el archivo de configuracion");
		return 1;
	}
	iniciarSesionLDAP();
	ctx = InitServerCTX();
	LoadCertificates(ctx, pathServerKEY, pathServerKEY);
	server = OpenListener(puertoSSL);/*(5000);*/
	while (1){
		struct sockaddr_in addr;
		int len = sizeof(addr);
		SSL *ssl;
		int client = accept(server, (struct sockaddr*)&addr, &len);
		printf("Recibida conexion de: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
		escribirLog("NNTPServerBAM",PID,"INFO:Conexion Recibida");
		ssl = SSL_new(ctx);
		SSL_set_fd(ssl, client);
		Servlet(ssl);
	}
	close(server);
	SSL_CTX_free(ctx);
}

char* procesoComandos (char* comando, char* parametro,SSL* ssl){

	entroif= 0;

	if (strcmp(comando,"list") == 0 && strcmp(parametro,"newsgroups") == 0){                        
		listarNewsgroups(ssl);                                
		entroif=1;
		return("listgroup grupo" );
	}

	if ((strcmp(comando,"listgroup") == 0) && (strcmp(parametro," ") != 0)){ 
		printf ("Listgroup");
		entroif=1;
		listarArticles(ssl,parametro);
		return("listgroup grupo" );
	}

	if (strcmp(comando,"help") == 0){
		entroif=1;
		funcionHelp(ssl);
		return("help grupo" );
	}

	if (strcmp(comando,"quit") == 0){
		entroif=1;
		quit(ssl);
		return("quit" );
	}

	if ((strcmp(comando,"article") == 0) && (strcmp(parametro," ") != 0)){
		entroif=1;
		mostrarArticle(ssl,parametro);
		return("article grupo" );
	}

	if ((strcmp(comando,"stat") == 0) && (strcmp(parametro," ") != 0)){
		entroif=1;
		mostrarStat(ssl, parametro);
		return("stat grupo" );
	}

	if ((strcmp(comando,"head") == 0) && (strcmp(parametro," ") != 0)){
		entroif=1;
		mostrarHead(ssl, parametro);
		return("head grupo" );
	}

	if ((strcmp(comando,"body") == 0) && (strcmp(parametro," ") != 0)){
		entroif=1;
		mostrarBody(ssl,parametro);
		return("body grupo" );
	}


	if (entroif != 1){
		char mensaje[32];
		strcpy(mensaje,"Comando no valido\r\n.\r\n");
		SSL_write(ssl,mensaje,32*sizeof(char));
		printf("%s",mensaje);
	}

}

void Servlet(SSL* ssl){

char buf[1024];
char reply[1024];
int sd, bytes;
char parametro[1024],comandoLimpio[1024];
char *punteroACorte, *comandoSucio;

punteroACorte = (char *) malloc (sizeof(char)*1024);
comandoSucio = (char *) malloc (sizeof(char)*1024);

	if ( SSL_accept(ssl) == -1 )
		ERR_print_errors_fp(stderr);
	else{
		ShowCerts(ssl);
		do {
			bytes = SSL_read(ssl, buf, sizeof(buf));
			if ( bytes > 0 ){

				buf[bytes] = '\0';
				printf("Recibido: %s\n", buf);
				memset(parametro,"\0",1024);
				memset(comandoLimpio,"\0",1024);
				memset(grupo,"\0",1024);
				memset(articleID,"\0",1024);
				comandoSucio =  strtok(buf," ");

				if ((punteroACorte = strtok(NULL," "))==NULL){
					strcpy(comandoLimpio,strtok(buf,"\r\n"));
				}else{
					if (strcmp(punteroACorte,"\r\n")!=0){
						strcpy(comandoLimpio,comandoSucio);
	  					strcpy(parametro,strtok(punteroACorte,"\r\n"));
	  				}else{
						strcpy(comandoLimpio,strtok(buf,"\r\n"));
						strcpy(parametro," ");
						}
				}
				procesoComandos(comandoLimpio,parametro,ssl);

			}else {
				ERR_print_errors_fp(stderr);
			}
	
		} while (strcmp(comandoLimpio, "quit")!=0);
	}
	sd = SSL_get_fd(ssl);
	SSL_free(ssl);
	close(sd);
}


void ShowCerts(SSL* ssl)
{
	X509 *cert;
	char *line;

	cert = SSL_get_peer_certificate(ssl);
	if ( cert != NULL )
	{
		printf("Certificados del servidor:\n");
		line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
		printf("\tAsunto: %s\n", line);
		free(line);
		line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
		printf("\tProvisto por: %s\n", line);
		escribirLog("NNTPServerBAM",PID,"INFO: Se conecto al servidor usando SSL");
		free(line);
		X509_free(cert);
	} else {
		printf("El cliente se conecto sin presentar certificado\n");
		escribirLog("NNTPServerBAM",PID,"INFO:El cliente se conecto sin presentar certificado");
	}
}

void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
	if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
	{
		ERR_print_errors_fp(stderr);
		abort();
	}

	if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
	{
		ERR_print_errors_fp(stderr);
		abort();
	}

	if ( !SSL_CTX_check_private_key(ctx) )
	{
		escribirLog("NNTPServerBAM",PID,"ERROR: No coincide la clave privada con el certificado publico");
		abort();
	}
}

SSL_CTX* InitServerCTX(void)
{

	SSL_METHOD *method;
	SSL_CTX *ctx;

	SSL_library_init();
	OpenSSL_add_all_algorithms();
	SSL_load_error_strings();
	method = SSLv23_server_method();
	ctx = SSL_CTX_new(method);
	if ( ctx == NULL )
	{
		ERR_print_errors_fp(stderr);
		escribirLog("NNTPServerBAM",PID,"ERROR: Fallo la inicializacion de contexto SSL");
		abort();
	}
	return ctx;
}

int OpenListener(int port)
{
	int sd;
	struct sockaddr_in addr;

	sd = socket(PF_INET, SOCK_STREAM, 0);
	bzero(&addr, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = INADDR_ANY;
	if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
	{
		perror("bind");
		escribirLog("NNTPServerBAM",PID,"ERROR: Bind");
		abort();
	}
	if ( listen(sd, 10) != 0 )
	{
		perror("listen");
		escribirLog("NNTPServerBAM",PID,"ERROR: Listen");
		abort();
	}
	return sd;
}

int iniciarSesionLDAP() {
    sesion.ldapHost        =  ipLDAP;
    sesion.ldapPort        =  atoi(LDAP_Port);
    sesion.loginDN         =  LDAP_DN;
    sesion.password        =  LDAP_Pass;

    sesion.version = LDAP_VERSION3;
    ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &(sesion.version));

    /* Inicializa sesion LDAP */
    if (( sesion.ld = ldap_init( sesion.ldapHost, sesion.ldapPort )) == NULL)
    {
        printf("\n\tLDAP session initialization failed\n");
		escribirLog("NNTPServerBAM",PID,"INFO:LDAP session initialization failed");
        return( 1 );
    }
    printf ( "\n\tLDAP session initialized\n");
    escribirLog("NNTPServerBAM",PID,"INFO:LDAP session initialized");
   
    /* Bind  */
    sesion.rc = ldap_simple_bind_s( sesion.ld, sesion.loginDN, sesion.password );
    if (sesion.rc != LDAP_SUCCESS )
    {
        printf("ldap_simple_bind_s: %s\n", ldap_err2string( sesion.rc ));
        ldap_unbind_s ( sesion.ld );
        return( 1 );
    }
    printf("\n\tBind successful as [%s]\n", sesion.loginDN);
    escribirLog("NNTPServerBAM",PID,"INFO:LDAP Bind successful ");
    return(0);
}

int cerrarSesionLDAP() {
	/* Cierro la session con el servidor */
	ldap_unbind_s(sesion.ld);
	escribirLog("NNTPServerBAM",PID,"INFO:Cierra session LDAP");

	return 0;
}

int listarNewsgroups(SSL* socket) {
    char *searchBase, *attribute, **values, *listaOriginal, *listaLimpia,*aux;
    BerElement  *ber;
    LDAPMessage *searchResult, *entry;
    char filter[128],campo[128],mensajeLista[1024];
    int i, entryCount;

    listaOriginal = (char *)malloc(sizeof(char)*9999);
    listaLimpia = (char *)malloc(sizeof(char)*9999);

	memset(mensajeLista,'\0',1024);
	memset(listaLimpia,'\0',1024);
    memset(listaOriginal,'\0',1024);

    searchBase = "ou=so,dn=utn,dn=edu";
    strcpy(filter,"(utnArticleGroupName=*)");

   /* Search the directory */
	sesion.rc = ldap_search_ext_s(
                    sesion.ld,             /* LDAP session handle */
                    searchBase,            /* container to search */
                    LDAP_SCOPE_SUBTREE,    /* search scope */
                    filter,                /* search filter */
                    NULL,                  /* return all attributes */
                    0,                     /* return attributes and values */
                    NULL,                  /* server controls */
                    NULL,                  /* client controls */
                    LDAP_NO_LIMIT,         /* search timeout */
                    LDAP_NO_LIMIT,         /* no size limit */
                    &searchResult );       /* returned results */

    if ( sesion.rc != LDAP_SUCCESS ) {
        printf("ldap_search_ext_s: %s\n", ldap_err2string( sesion.rc ));
        ldap_msgfree( searchResult );
        return ( 1 );
    }

    /* Este es el for que itera por entradas */
    for (   entry   =   ldap_first_entry( sesion.ld, searchResult );
            entry   !=  NULL;
            entry   =   ldap_next_entry( sesion.ld, entry ) )
    {
        /* Se toma el dn de la entrada corriente */
        if (( sesion.dn = ldap_get_dn( sesion.ld, entry )) != NULL ) {
            printf("\n   dn: %s\n", sesion.dn );
            ldap_memfree( sesion.dn );
        }

        /* Este es el for que itera por los attributos por una entrada dada
          Para la entrada corriente se recorren los atributos */
        attribute = ldap_first_attribute( sesion.ld, entry, &ber );
        if (( values = ldap_get_values( sesion.ld, entry, attribute)) != NULL ){
            printf("        %s: %s\n", attribute, values[0] );
            strcat(listaOriginal,values[0]);
            strcat(listaOriginal,"$#");

            /* Se liberan las estructuras creadas por la ldap API */
            ldap_value_free( values );
        }

        ldap_memfree( attribute );

    }
    ber_free(ber, 0);
    strcat(listaOriginal,"##");
    eliminarDuplicados(listaOriginal, listaLimpia);

    /* Para saber el numero de entrdas devueltas por la busqueda */
    entryCount = ldap_count_entries( sesion.ld, searchResult );
    printf("\n    Search completed successfully.\n    Entries  returned: %d\n", entryCount);

    /* tratamiento de la lista limpia */
    strcpy(mensajeLista,"215 Lista de Newsgroups\r\n");
    aux = strtok(listaLimpia,"$#");
        while(aux != NULL) {
            strcat(mensajeLista,aux);
            strcat(mensajeLista,"\r\n");
            aux = strtok(NULL,"$#");
        }
    strcat(mensajeLista,".\r\n");
    SSL_write(socket,mensajeLista,(strlen(mensajeLista)));

    ldap_msgfree( searchResult );
    return 0;
}

void eliminarDuplicados(char *listaOriginal, char *listaLimpia) {
    char *aux;
    aux = (char *)malloc(sizeof(char)*1024);

    aux = strtok(listaOriginal,"$#");
    strcat(listaLimpia,aux);
    while(aux != NULL) {
        if (strstr(listaLimpia,aux) == NULL) {
            strcat(listaLimpia,"$#");
            strcat(listaLimpia,aux);
        }
        aux = strtok(NULL,"$#");
    }
    free(aux);
}


void quit(SSL *ssl){
    char mensaje[1024];
    memset(mensaje,'\0',1024);
    strcpy (mensaje,"205 Se cierra la conexion con Server Desincronizados\r\n.\r\n");
    SSL_write(ssl,mensaje,(strlen(mensaje)));
}


int listarArticles(SSL* ssl, char *groupName) {   /* el cliente envia listgroup*/
    char *searchBase, *attribute, **values, *lista, *titulo, *aux;
    BerElement  *ber;
    LDAPMessage *searchResult, *entry;
    char filter[128],campo[128],mensaje[1024];
    int i, entryCount;

    lista = (char *)malloc(sizeof(char)*9999);
    titulo = (char *)malloc(sizeof(char)*1024);

    memset(mensaje,'\0',1024);
    memset(lista,'\0',1024);
    searchBase = "ou=so,dn=utn,dn=edu";
    strcpy(filter, "(utnArticleGroupName=");
    strcat(filter,groupName);
    strcat(filter,")");

   /* Search the directory */
   sesion.rc = ldap_search_ext_s(
                    sesion.ld,             /* LDAP session handle */
                    searchBase,            /* container to search */
                    LDAP_SCOPE_SUBTREE,    /* search scope */
                    filter,                /* search filter */
                    NULL,                  /* return all attributes */
                    0,                     /* return attributes and values */
                    NULL,                  /* server controls */
                    NULL,                  /* client controls */
                    LDAP_NO_LIMIT,         /* search timeout */
                    LDAP_NO_LIMIT,         /* no size limit */
                    &searchResult );       /* returned results */

    if ( sesion.rc != LDAP_SUCCESS ) {
        printf("ldap_search_ext_s: %s\n", ldap_err2string( sesion.rc ));
        ldap_msgfree( searchResult );
        return ( 1 );
    }

    /* Este es el for que itera por entradas */
    for (   entry   =   ldap_first_entry( sesion.ld, searchResult );
            entry   !=  NULL;
            entry   =   ldap_next_entry( sesion.ld, entry ) )
    {
        /* Se toma el dn de la entrada corriente */
        if (( sesion.dn = ldap_get_dn( sesion.ld, entry )) != NULL ) {
            printf("\n   dn: %s\n", sesion.dn );
            ldap_memfree( sesion.dn );
        }

        /* Este es el for que itera por los attributos por una entrada dada
          Para la entrada corriente se recorren los atributos */
        for (   attribute = ldap_first_attribute( sesion.ld, entry, &ber );
                attribute != NULL;
                attribute = ldap_next_attribute( sesion.ld, entry, ber ) )
        {

            if (strcmp(attribute,"utnArticleID") == 0) {
                if (( values = ldap_get_values( sesion.ld, entry, attribute)) != NULL ){
                    strcat(lista,"<");
                    strcat(lista,values[0]);
                    strcat(lista,"@");
                    strcat(lista,groupName);
                    strcat(lista,">");

                    strcat(lista, "\r\n");
                    /* Se liberan las estructuras creadas por la ldap API */
                    ldap_value_free( values );
                }
            }
            ldap_memfree( attribute );

        }
        ber_free(ber, 0);
    }
    /* Para saber el numero de entrdas devueltas por la busqueda */
    entryCount = ldap_count_entries( sesion.ld, searchResult );
    printf("\n    Search completed successfully.\n    Entries  returned: %d\n",
             entryCount);

    if (entryCount > 0){
        strcpy(mensaje, "211 Lista de articulos de ");
        strcat(mensaje, groupName);
        strcat(mensaje, " selected\r\n");
        strcat(mensaje,lista);
        strcat(mensaje,".\r\n");       
    }
    else{
        strcat(mensaje, "412 no existe dicho grupo\r\n");
    }

    SSL_write(ssl,mensaje,(strlen(mensaje)));
    ldap_msgfree( searchResult );
    return 0;
}

int funcionHelp(SSL *ssl){
    char mensajeHelp[1024];
    memset(mensajeHelp, '\0', 1024);

    strcat (mensajeHelp, "Comandos implementados : \n");
    strcat (mensajeHelp, " - list newsgroups\n");
    strcat (mensajeHelp, " - listgroup [<nombre del grupo>]\n");
    strcat (mensajeHelp, " - article [<messageID>]\n");
    strcat (mensajeHelp, " - body [<messageID>]\n");
    strcat (mensajeHelp, " - head [<messageID]\n");
    strcat (mensajeHelp, " - quit\n");
    strcat (mensajeHelp, " - help\n");
    strcat (mensajeHelp, " Grupo Desincronizados - 1c 2010 " );
    strcat(mensajeHelp,"\r\n.\r\n");
    SSL_write (ssl, mensajeHelp, (strlen(mensajeHelp)));

}

void cadenaID (char *mensajeID){

    char str2[1024], *p, *fin,*finStrTok;
    int SIZE;

    p = mensajeID + 1;
	SIZE = strlen (mensajeID) ;
	fin = SIZE -1;
    memmove(mensajeID, p, fin);
    memset(str2,'\0',1024);
    memcpy(str2,mensajeID,SIZE-2);
    printf("result after shift: %s\n", str2);
    strcpy(articleID,strtok(str2, "@"));
    if ((finStrTok=strtok(NULL, "@")) == NULL){
    	strcpy(grupo, "@#~#~½");
    	strcpy(articleID,"½¬~#½#");
    } else {
    strcpy(articleID,strtok(str2, "@"));
    strcpy(grupo,finStrTok);
	}

}

int mostrarArticle(SSL * ssl, char *mensajeID) {   /* el cliente envia listgroup*/
    char *searchBase, *attribute, **values, *lista, *titulo, *articleHead, *articleBody;
    BerElement  *ber;
    LDAPMessage *searchResult, *entry;
    char filter[128],campo[128],mensajeLista[1024];
    int i, entryCount;

    lista = (char *)malloc(sizeof(char)*9999);
    titulo = (char *)malloc(sizeof(char)*1024);
    articleHead = (char *)malloc(sizeof(char)*1024);
    articleBody = (char *)malloc(sizeof(char)*1024);
    

    cadenaID (mensajeID);

    memset(mensajeLista,'\0',1024);
    memset(lista,'\0',1024);
    searchBase = "ou=so,dn=utn,dn=edu";
    strcpy(filter, "(&(utnArticleGroupName=");
    strcat(filter,grupo);
    strcat(filter,")(utnArticleID=");
    strcat(filter,articleID);
    strcat(filter,"))");

   /* Search the directory */
    sesion.rc = ldap_search_ext_s(
                    sesion.ld,             /* LDAP session handle */
                    searchBase,            /* container to search */
                    LDAP_SCOPE_SUBTREE,    /* search scope */
                    filter,                /* search filter */
                    NULL,                  /* return all attributes */
                    0,                     /* return attributes and values */
                    NULL,                  /* server controls */
                    NULL,                  /* client controls */
                    LDAP_NO_LIMIT,         /* search timeout */
                    LDAP_NO_LIMIT,         /* no size limit */
                    &searchResult );       /* returned results */

    if ( sesion.rc != LDAP_SUCCESS )
    {
        printf("ldap_search_ext_s: %s\n", ldap_err2string( sesion.rc ));
        ldap_msgfree( searchResult );
        return ( 1 );
    }

    /* Este es el for que itera por entradas */
    for (   entry   =   ldap_first_entry( sesion.ld, searchResult );
            entry   !=  NULL;
            entry   =   ldap_next_entry( sesion.ld, entry ) )
    {
        /* Se toma el dn de la entrada corriente */
        if (( sesion.dn = ldap_get_dn( sesion.ld, entry )) != NULL ) {
            printf("\n   dn: %s\n", sesion.dn );
            ldap_memfree( sesion.dn );
        }

        /* Este es el for que itera por los attributos por una entrada dada
          Para la entrada corriente se recorren los atributos */
        for (   attribute = ldap_first_attribute( sesion.ld, entry, &ber );
                attribute != NULL;
                attribute = ldap_next_attribute( sesion.ld, entry, ber ) )
        {

            if (strcmp(attribute,"utnArticleHead") == 0) {
                if (( values = ldap_get_values( sesion.ld, entry, attribute)) != NULL ){
                    strcpy(articleHead,values[0]);
                    /* Se liberan las estructuras creadas por la ldap API */
                    ldap_value_free( values );
                }
            }


            if (strcmp(attribute,"utnArticleBody") == 0){
                if (( values = ldap_get_values( sesion.ld, entry, attribute)) != NULL ){
                    strcpy(articleBody,values[0]);

                    ldap_value_free( values );
                }
            }
            ldap_memfree( attribute );                           
        }
        ber_free(ber, 0);
    }
    /* Para saber el numero de entrdas devueltas por la busqueda */
    entryCount = ldap_count_entries( sesion.ld, searchResult );
    printf("\n    Search completed successfully.\n    Entries  returned: %d\n",
             entryCount);



    if (entryCount > 0){
        memset(titulo,'\0',1024);
        strcat(titulo, "220 <");
        strcat(titulo,articleID);
        strcat(titulo,"@");
        strcat(titulo,grupo);
        strcat(titulo,"> - Head y body a continuacion\r\n");
        /*strcat(titulo,articleHead);*/
		strcpy(mensajeLista, titulo);
		strcat(mensajeLista, articleHead);
		strcat(mensajeLista, "\r\n\r\n");	
		strcat(mensajeLista, articleBody);		
		strcat(mensajeLista,"\r\n.\r\n");
    }
    else{
        strcat(mensajeLista,"423 no such article number in this group \r\n");
    }

    SSL_write(ssl,mensajeLista,(strlen(mensajeLista)));
    ldap_msgfree( searchResult );
    return 0;
}

int mostrarBody(SSL * ssl, char *mensajeID) {   /* el cliente envia listgroup*/
    char *searchBase, *attribute, **values, *lista, *titulo, *articleBody;
    BerElement  *ber;
    LDAPMessage *searchResult, *entry;
    char filter[128],campo[128],mensajeLista[1024];
    int i, entryCount;

    lista = (char *)malloc(sizeof(char)*9999);
    titulo = (char *)malloc(sizeof(char)*1024);
    articleBody = (char *)malloc(sizeof(char)*1024);

    cadenaID (mensajeID);

    memset(mensajeLista,'\0',1024);
    memset(lista,'\0',1024);
    searchBase = "ou=so,dn=utn,dn=edu";
    strcpy(filter, "(&(utnArticleGroupName=");
    strcat(filter,grupo);
    strcat(filter,")(utnArticleID=");
    strcat(filter,articleID);
    strcat(filter,"))");

   /* Search the directory */
    sesion.rc = ldap_search_ext_s(
                    sesion.ld,             /* LDAP session handle */
                    searchBase,            /* container to search */
                    LDAP_SCOPE_SUBTREE,    /* search scope */
                    filter,                /* search filter */
                    NULL,                  /* return all attributes */
                    0,                     /* return attributes and values */
                    NULL,                  /* server controls */
                    NULL,                  /* client controls */
                    LDAP_NO_LIMIT,         /* search timeout */
                    LDAP_NO_LIMIT,         /* no size limit */
                    &searchResult );       /* returned results */

    if ( sesion.rc != LDAP_SUCCESS )
    {
        printf("ldap_search_ext_s: %s\n", ldap_err2string( sesion.rc ));
        ldap_msgfree( searchResult );
        return ( 1 );
    }

    /* Este es el for que itera por entradas */
    for (   entry   =   ldap_first_entry( sesion.ld, searchResult );
            entry   !=  NULL;
            entry   =   ldap_next_entry( sesion.ld, entry ) )
    {
        /* Se toma el dn de la entrada corriente */
        if (( sesion.dn = ldap_get_dn( sesion.ld, entry )) != NULL ) {
            printf("\n   dn: %s\n", sesion.dn );
            ldap_memfree( sesion.dn );
        }

        /* Este es el for que itera por los attributos por una entrada dada
          Para la entrada corriente se recorren los atributos */
        for (   attribute = ldap_first_attribute( sesion.ld, entry, &ber );
                attribute != NULL;
                attribute = ldap_next_attribute( sesion.ld, entry, ber ) )
        {

            if (strcmp(attribute,"utnArticleBody") == 0){
                if (( values = ldap_get_values( sesion.ld, entry, attribute)) != NULL ){
                    strcat(lista,values[0]);

                    ldap_value_free( values );
                }
            }
            ldap_memfree( attribute );
                    
        }
        ber_free(ber, 0);
    }
    /* Para saber el numero de entrdas devueltas por la busqueda */
    entryCount = ldap_count_entries( sesion.ld, searchResult );
    printf("\n    Search completed successfully.\n    Entries  returned: %d\n",
             entryCount);



    if (entryCount > 0){
        memset(titulo,'\0',1024);
        strcat(titulo,articleID);
        strcat(titulo,"\n");
        strcat(titulo,grupo);
        strcat(titulo,"\n");
		strcpy(mensajeLista, titulo);
        strcat(mensajeLista, "\r\n");
		strcat(mensajeLista, lista);
		strcat(mensajeLista,"\r\n.\r\n");
    }
    else{
        strcat(mensajeLista,"423 no such article number in this group \r\n");
    }

    SSL_write(ssl,mensajeLista,(strlen(mensajeLista)));
    ldap_msgfree( searchResult );
    return 0;
}

int mostrarHead(SSL * ssl, char *mensajeID) {   /* el cliente envia head mesajeID*/
    char *searchBase, *attribute, **values,*articleHead;
    BerElement  *ber;
    LDAPMessage *searchResult, *entry;
    char filter[128],campo[128],mensajeLista[1024];
    int i, entryCount;

    articleHead = (char *)malloc(sizeof(char)*1024);
    cadenaID (mensajeID);

    memset(mensajeLista,'\0',1024);
    memset(articleHead,'\0',1024);

    searchBase = "ou=so,dn=utn,dn=edu";
    strcpy(filter, "(&(utnArticleGroupName=");
    strcat(filter,grupo);
    strcat(filter,")(utnArticleID=");
    strcat(filter,articleID);
    strcat(filter,"))");

   /* Search the directory */
    sesion.rc = ldap_search_ext_s(
                    sesion.ld,             /* LDAP session handle */
                    searchBase,            /* container to search */
                    LDAP_SCOPE_SUBTREE,    /* search scope */
                    filter,                /* search filter */
                    NULL,                  /* return all attributes */
                    0,                     /* return attributes and values */
                    NULL,                  /* server controls */
                    NULL,                  /* client controls */
                    LDAP_NO_LIMIT,         /* search timeout */
                    LDAP_NO_LIMIT,         /* no size limit */
                    &searchResult );       /* returned results */

    if ( sesion.rc != LDAP_SUCCESS )
    {
        printf("ldap_search_ext_s: %s\n", ldap_err2string( sesion.rc ));
        ldap_msgfree( searchResult );
        return ( 1 );
    }

    /* Este es el for que itera por entradas */
    for (   entry   =   ldap_first_entry( sesion.ld, searchResult );
            entry   !=  NULL;
            entry   =   ldap_next_entry( sesion.ld, entry ) )
    {
        /* Se toma el dn de la entrada corriente */
        if (( sesion.dn = ldap_get_dn( sesion.ld, entry )) != NULL ) {
            printf("\n   dn: %s\n", sesion.dn );
            ldap_memfree( sesion.dn );
        }

        /* Este es el for que itera por los attributos por una entrada dada
          Para la entrada corriente se recorren los atributos */
        for (   attribute = ldap_first_attribute( sesion.ld, entry, &ber );
                attribute != NULL;
                attribute = ldap_next_attribute( sesion.ld, entry, ber ) )
        {

            if (strcmp(attribute,"utnArticleHead") == 0) {
                if (( values = ldap_get_values( sesion.ld, entry, attribute)) != NULL ){
                        strcpy(articleHead,values[0]);
                        /* Se liberan las estructuras creadas por la ldap API */
                        ldap_value_free( values );
                }
            }


              ldap_memfree( attribute );
        }
        ber_free(ber, 0);
    }
    /* Para saber el numero de entrdas devueltas por la busqueda */
    entryCount = ldap_count_entries( sesion.ld, searchResult );
    printf("\n    Search completed successfully.\n    Entries  returned: %d\n",
             entryCount);

    if (entryCount > 0){
		strcat(mensajeLista, articleHead);
		strcat(mensajeLista,"\r\n.\r\n");
    }
    else{
        strcat(mensajeLista,"423 no such head  \r\n");
    }

    SSL_write(ssl,mensajeLista,(strlen(mensajeLista)));
    ldap_msgfree( searchResult );
    return 0;
}

int mostrarStat(SSL * ssl, char *mensajeID) {   
    char *searchBase, *attribute, **values;
    BerElement  *ber;
    LDAPMessage *searchResult, *entry;
    char filter[128],campo[128],mensajeLista[1024];
    int i, entryCount;

    cadenaID (mensajeID);

    memset(mensajeLista,'\0',1024);

    searchBase = "ou=so,dn=utn,dn=edu";
    strcpy(filter, "(&(utnArticleGroupName=");
    strcat(filter,grupo);
    strcat(filter,")(utnArticleID=");
    strcat(filter,articleID);
    strcat(filter,"))");

   /* Search the directory */
   sesion.rc = ldap_search_ext_s(
                    sesion.ld,             /* LDAP session handle */
                    searchBase,            /* container to search */
                    LDAP_SCOPE_SUBTREE,    /* search scope */
                    filter,                /* search filter */
                    NULL,                  /* return all attributes */
                    0,                     /* return attributes and values */
                    NULL,                  /* server controls */
                    NULL,                  /* client controls */
                    LDAP_NO_LIMIT,         /* search timeout */
                    LDAP_NO_LIMIT,         /* no size limit */
                    &searchResult );       /* returned results */

    if ( sesion.rc != LDAP_SUCCESS )
    {
        printf("ldap_search_ext_s: %s\n", ldap_err2string( sesion.rc ));
        ldap_msgfree( searchResult );
        return ( 1 );
    }
    /* Este es el for que itera por entradas */
    for (   entry   =   ldap_first_entry( sesion.ld, searchResult );
            entry   !=  NULL;
            entry   =   ldap_next_entry( sesion.ld, entry ) )
    {
	
        /* Se toma el dn de la entrada corriente */
        if (( sesion.dn = ldap_get_dn( sesion.ld, entry )) != NULL ) {
            printf("\n   dn: %s\n", sesion.dn );
            ldap_memfree( sesion.dn );
        }
        /* Este es el for que itera por los attributos por una entrada dada
          Para la entrada corriente se recorren los atributos */
        for (   attribute = ldap_first_attribute( sesion.ld, entry, &ber );
                attribute != NULL;
                attribute = ldap_next_attribute( sesion.ld, entry, ber ) )
        {
		
		

            if (strcmp(attribute,"utnArticleID") == 0){
                if (( values = ldap_get_values( sesion.ld, entry, attribute)) != NULL ){
                        /* Se liberan las estructuras creadas por la ldap API */
                        ldap_value_free( values );
                }
            }
            ldap_memfree( attribute );
        }
        ber_free(ber, 0);
    }
    /* Para saber el numero de entrdas devueltas por la busqueda */
    entryCount = ldap_count_entries( sesion.ld, searchResult );
    printf("\n    Search completed successfully.\n    Entries  returned: %d\n",
             entryCount);

    if (entryCount == 1){
		strcat(mensajeLista, "223 0 <");
		strcat (mensajeLista, articleID);
		strcat (mensajeLista, "@");
		strcat (mensajeLista, grupo);
        strcat (mensajeLista, ">");
        strcat(mensajeLista,"\r\n.\r\n");
    }
    else{
	if (entryCount > 1){/*articulos repetidos*/
		strcat(mensajeLista, "223 ");
		strcat(mensajeLista, entryCount);
		strcat(mensajeLista, " <");
        strcat (mensajeLista, articleID);
		strcat (mensajeLista, "@");
		strcat (mensajeLista, grupo);
        strcat (mensajeLista, ">");
		strcat(mensajeLista,"\r\n.\r\n");
	}
	else{
        strcat(mensajeLista,"430 no article with that message-id  \r\n");
    }
	}
    SSL_write(ssl,mensajeLista,(strlen(mensajeLista)));
    ldap_msgfree( searchResult );
    return 0;
}



int obtenerDatosConfig(void){
	FILE* arch;
	char cad[300+2];
	char* paux;

	if ((arch=fopen("ServerConfig.txt","rt")) == NULL) {
		printf("Error al abrir el archivo de configuracion. Se detiene la ejecucion\n");
		escribirLog("NNTPServerBAM",PID,"ERROR: No se pudo abrir el archivo de configuracion. Se detiene la ejecucion");		
		return 1;
	}
 

	if (fgets(cad,300+2,arch) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}

	if ((paux=strtok(cad,":")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}
	if ((paux=strtok(NULL,"\n\0")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}
	puertoSSL=atoi(paux);
	memset(cad,'\0',302);

	if (fgets(cad,300+2,arch) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}

	if ((paux=strtok(cad,":")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}
	if ((paux=strtok(NULL,"\n\0")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}
	strcpy(pathServerKEY,paux);
	memset(cad,'\0',302);
	
	if (fgets(cad,300+2,arch) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}
		
	if ((paux=strtok(cad,":")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}
	if ((paux=strtok(NULL, "\n\0")) == NULL){
		printf("El Archivo de Configuracion esta incompleto\n");
		return 1;
	}
	strcpy(ipLDAP,paux);
	memset(cad,'\0',302);

	if (fgets(cad,300+2,arch) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");		
		return 1;
	}

	if ((paux=strtok(cad,":")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");
		return 1;
	}
	if ((paux=strtok(NULL,"\n\0")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");
		return 1;
	}
	strcpy(LDAP_Port,paux);
	memset(cad,'\0',302);

	if (fgets(cad,300+2,arch) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");
		return 1;
	}

	if ((paux=strtok(cad,":")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");
		return 1;
	}
	if ((paux=strtok(NULL,"\n\0")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");
		return 1;
	}
	strcpy(LDAP_DN,paux);
	memset(cad,'\0',302);

	if (fgets(cad,300+2,arch) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");
		return 1;
	}

	if ((paux=strtok(cad,":")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");
		return 1;
	}
	if ((paux=strtok(NULL,"\n\0")) == NULL) {
		printf("El Archivo de Configuracion esta incompleto\n");
		escribirLog("Webserver",PID,"ERROR: El Archivo de Configuracion esta incompleto ");
		return 1;
	}
	strcpy(LDAP_Pass,paux);	
	

	fclose(arch);
	return 0;
}



/*
       __
w    c(..)o  (
 \ __ (-)   __)
       /\  (
      /(_)__)
      w /|
       | \
       m  m
*/